/*
 * CmdsWindow.h
 *
 *  Created on: 2024年9月14日
 *      Author: nwz
 */

#ifndef CODE_CMDSWINDOW_H_
#define CODE_CMDSWINDOW_H_

class CmdsWindow: public wxDialog {
public:
	CmdsWindow(wxWindow *parent) :
			parent { parent } {

	}
	virtual ~CmdsWindow() {

	}

	void init() {
		Create(parent, wxID_ANY, _("Commands"), wxDefaultPosition,
				wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER);

		auto lay = new wxBoxSizer(wxVERTICAL);

		{
			// data view
			menu_listview = createMenuListView();
			cmd_listview = createCmdListView();

			auto lay2 = new wxBoxSizer(wxHORIZONTAL);
			lay2->Add(menu_listview, wxSizerFlags(1).Expand().Border(wxALL, 7));
			lay2->Add(cmd_listview, wxSizerFlags(2).Expand().Border(wxALL, 7));
			lay->Add(lay2, wxSizerFlags(1).Expand());

			menu_listview->Connect(wxEVT_COMMAND_DATAVIEW_ITEM_CONTEXT_MENU,
					wxDataViewEventHandler(CmdsWindow::onContextMenu), NULL,
					this);
			cmd_listview->Connect(wxEVT_COMMAND_DATAVIEW_ITEM_CONTEXT_MENU,
					wxDataViewEventHandler(CmdsWindow::onContextMenu), NULL,
					this);
		}

		{
			auto btnOk = new wxButton(this, wxID_OK, _("OK"));
			auto btnCancel = new wxButton(this, wxID_CANCEL, _("Cancel"));

			auto lay2 = new wxBoxSizer(wxHORIZONTAL);
			lay2->Add(btnOk, wxSizerFlags().Border(wxALL, 7));
			lay2->Add(btnCancel, wxSizerFlags().Border(wxALL, 7));

			lay->Add(lay2, wxSizerFlags().Center());
		}
		SetSizer(lay);
		Layout();
		////
		menu_listview->Connect(wxEVT_COMMAND_DATAVIEW_SELECTION_CHANGED,
				wxDataViewEventHandler(CmdsWindow::onSelectionChanged), NULL,
				this);
		menu_listview->Connect(wxEVT_COMMAND_DATAVIEW_ITEM_EDITING_DONE,
				wxDataViewEventHandler(CmdsWindow::onEditDone), NULL, this);
		cmd_listview->Connect(wxEVT_COMMAND_DATAVIEW_ITEM_EDITING_DONE,
				wxDataViewEventHandler(CmdsWindow::onEditDone), NULL, this);
		/// bind menu
		this->Bind(wxEVT_MENU, &CmdsWindow::onMenu, this, ID_MENU_ADD_MENU);
		this->Bind(wxEVT_MENU, &CmdsWindow::onMenu, this, ID_MENU_ADD_CMD);
		this->Bind(wxEVT_MENU, &CmdsWindow::onMenu, this, ID_MENU_DEL_MENU);
		this->Bind(wxEVT_MENU, &CmdsWindow::onMenu, this, ID_MENU_DEL_CMD);
		this->Bind(wxEVT_MENU, &CmdsWindow::onMenu, this, ID_MENU_SAVE_CMD);
		this->Bind(wxEVT_MENU, &CmdsWindow::onMenu, this, ID_MENU_SAVE_MENU);

	}

	void reset(std::vector<struct table_menu> &menus,
			std::vector<struct table_menu_cmd> &cmds) {
		this->menus.clear();
		this->cmds.clear();
		ids.clear();

		for (auto menu : menus) {
			this->menus.push_back(menu);
			ids.insert(menu.id);
		}
		for (auto cmd : cmds) {
			this->cmds.push_back(cmd);
			ids.insert(cmd.id);
		}

		menu_listview->DeleteAllItems();
		cmd_listview->DeleteAllItems();

		/// load data
		for (auto menu : menus) {
			wxVector<wxVariant> data;
			data.push_back(menu.id);
			data.push_back(_(menu.name.c_str()));
			data.push_back(menu.order_id);
			menu_listview->AppendItem(data);
		}
	}

	std::vector<struct table_menu> getMenus() {
		std::vector<struct table_menu> ms;
		for (auto menu : menus) {
			ms.push_back(menu);
		}
		return ms;
	}

	std::vector<struct table_menu_cmd> getMenuCmds() {
		std::vector<struct table_menu_cmd> cs;
		for (auto cmd : cmds) {
			cs.push_back(cmd);
		}
		return cs;
	}

private:
	enum {
		ID_MENU_LISTVIEW, //
		ID_CMD_LISTVIEW, //
		ID_MENU_DEL_MENU,
		ID_MENU_ADD_MENU, //
		ID_MENU_SAVE_MENU, //
		ID_MENU_DEL_CMD,
		ID_MENU_ADD_CMD,
		ID_MENU_SAVE_CMD,
	};

	wxWindow *parent;
	std::list<struct table_menu> menus;
	std::list<struct table_menu_cmd> cmds;
	std::unordered_set<int> ids;

	wxDataViewListCtrl *menu_listview;
	wxDataViewListCtrl *cmd_listview;

	int getNewId() {
		static int start_id = 1;
		while (ids.find(start_id) != ids.end()) {
			start_id += 1;
		}
		ids.insert(start_id);
		return start_id;
	}

	wxDataViewListCtrl* createMenuListView() {
		auto view = new wxDataViewListCtrl(this, ID_MENU_LISTVIEW);

		{ // column
			wxDataViewSpinRenderer *sr = new wxDataViewSpinRenderer(0, INT_MAX,
					wxDATAVIEW_CELL_INERT);
			wxDataViewColumn *column = new wxDataViewColumn(_("ID"), sr, 0,
					FromDIP(60), wxALIGN_LEFT,
					wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_REORDERABLE);

			view->AppendColumn(column);
		}
		{
			view->AppendTextColumn(_("Name"), wxDATAVIEW_CELL_EDITABLE,
					FromDIP(100));
		}
		{ // column
			wxDataViewSpinRenderer *sr = new wxDataViewSpinRenderer(0, INT_MAX,
					wxDATAVIEW_CELL_EDITABLE);
			wxDataViewColumn *column = new wxDataViewColumn(_("Order_Id"), sr,
					2, FromDIP(60), wxALIGN_LEFT,
					wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_REORDERABLE);

			view->AppendColumn(column);
		}

		return view;
	}

	wxDataViewListCtrl* createCmdListView() {
		auto view = new wxDataViewListCtrl(this, ID_CMD_LISTVIEW);

		{ // column
			wxDataViewSpinRenderer *sr = new wxDataViewSpinRenderer(0, INT_MAX,
					wxDATAVIEW_CELL_INERT);
			wxDataViewColumn *column = new wxDataViewColumn(_("ID"), sr, 0,
					FromDIP(60), wxALIGN_LEFT,
					wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_REORDERABLE);

			view->AppendColumn(column);
		}
		{ // column
			wxDataViewSpinRenderer *sr = new wxDataViewSpinRenderer(0, INT_MAX,
					wxDATAVIEW_CELL_INERT);
			wxDataViewColumn *column = new wxDataViewColumn(_("Menu_ID"), sr, 1,
					FromDIP(60), wxALIGN_LEFT,
					wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_REORDERABLE);

			view->AppendColumn(column);

		}
		{
			view->AppendTextColumn(_("Process_Name"), wxDATAVIEW_CELL_EDITABLE,
					FromDIP(200));
		}
		{
			view->AppendTextColumn(_("Process_Arg"), wxDATAVIEW_CELL_EDITABLE,
					FromDIP(200));
		}

		{ // column
			wxDataViewSpinRenderer *sr = new wxDataViewSpinRenderer(0, INT_MAX,
					wxDATAVIEW_CELL_EDITABLE);
			wxDataViewColumn *column = new wxDataViewColumn(_("Order_Id"), sr,
					4, FromDIP(100), wxALIGN_LEFT,
					wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_REORDERABLE);

			view->AppendColumn(column);
		}

		// hide menu_id
		return view;
	}

	void onContextMenu(wxDataViewEvent &event) {
		wxMenu menu;
		if (event.GetId() == ID_MENU_LISTVIEW) {
			menu.Append(ID_MENU_ADD_MENU, _("Add"));
			menu.Append(ID_MENU_DEL_MENU, _("Delete"));
		} else {
			menu.Append(ID_MENU_ADD_CMD, _("Add"));
			menu.Append(ID_MENU_DEL_CMD, _("Delete"));
		}
		PopupMenu(&menu);
	}

	void onMenu(wxCommandEvent &event) {
		auto id = event.GetId();

		auto selected_row = menu_listview->GetSelectedRow();
		auto selected_row_cmd = cmd_listview->GetSelectedRow();
		switch (id) {
		case ID_MENU_ADD_MENU: {
			wxVector<wxVariant> data;
			data.push_back(getNewId());
			data.push_back(_("name"));
			data.push_back(0);
			menu_listview->AppendItem(data);
			menus.push_back(
					{ data[0].GetInteger(), "", data[2].GetInteger() });
		}
			break;
		case ID_MENU_ADD_CMD:
			if (selected_row != wxNOT_FOUND) {
				wxVector<wxVariant> data;
				wxVariant variant;
				menu_listview->GetValue(variant, selected_row, 0);
				data.push_back(getNewId());
				data.push_back(variant.GetInteger());
				data.push_back(_("process_name"));
				data.push_back(_("process_arg"));
				data.push_back(0);
				cmd_listview->AppendItem(data);
				cmds.push_back( { data[0].GetInteger(), data[1].GetInteger(),
						"", "", data[4].GetInteger() });
			}
			break;
		case ID_MENU_DEL_MENU:
			if (selected_row != wxNOT_FOUND) {
				wxVariant variant;
				menu_listview->GetValue(variant, selected_row, 0);
				menus.remove_if([id = variant.GetInteger()](auto menu) {
					return menu.id == id;
				});
				menu_listview->DeleteItem(selected_row);
				cmds.remove_if([menu_id = variant.GetInteger()](auto cmd) {
					return cmd.menu_id == menu_id;
				});
				menu_listview->DeleteAllItems();
			}
			break;
		case ID_MENU_DEL_CMD:
			if (selected_row_cmd != wxNOT_FOUND) {
				wxVariant variant;
				cmd_listview->GetValue(variant, selected_row_cmd, 0);
				cmds.remove_if([id = variant.GetInteger()](auto cmd) {
					return cmd.id == id;
				});
				cmd_listview->DeleteItem(selected_row_cmd);
			}
			break;
		} // end switch
	}

	void onSelectionChanged(wxDataViewEvent &event) {
// set cmd list view
		cmd_listview->DeleteAllItems();
		auto selected = menu_listview->GetSelectedRow();
		if (selected != wxNOT_FOUND) {
			for (auto cmd : cmds) {
				wxVariant variant;
				menu_listview->GetValue(variant, selected, 0);
				if (cmd.menu_id == variant.GetInteger()) {
					// add this
					wxVector<wxVariant> data;
					data.push_back(cmd.id);
					data.push_back(variant.GetInteger());
					data.push_back(_(cmd.process_name.c_str()));
					data.push_back(_(cmd.process_arg.c_str()));
					data.push_back(cmd.order_id);
					cmd_listview->AppendItem(data);
				}
			}
		}
	}

	void onEditDone(wxDataViewEvent &event) {
		if (!event.IsEditCancelled()) {
			wxDataViewModel *const model = event.GetModel();
			auto row = event.GetItem();
			auto col = event.GetColumn();
			auto val = event.GetValue();
			switch (event.GetId()) {
			case ID_MENU_LISTVIEW: {
				wxVariant value[1];
				model->GetValue(value[0], row, 0);
				for (auto &menu : menus) {
					if (menu.id == value[0].GetInteger()) {
						switch (col) {
						case 1:
							menu.name = std::string(val.GetString().mb_str());
							break;
						case 2:
							menu.order_id = val.GetInteger();
							break;
						}
						break;
					}
				}
			}
				break;
			case ID_CMD_LISTVIEW: {
				wxVariant value[1];
				model->GetValue(value[0], row, 0);

				for (auto &cmd : cmds) {
					if (cmd.id == value[0].GetInteger()) {
						switch (col) {
						case 2:
							cmd.process_name = std::string(
									val.GetString().mb_str());
							break;
						case 3:
							cmd.process_arg = std::string(
									val.GetString().mb_str());
							break;
						case 4:
							cmd.order_id = val.GetInteger();
							break;
						}

						break;
					}
				}
			}
				break;
			} /// end switch
		}
	}
};

#endif /* CODE_CMDSWINDOW_H_ */
